package JUC.completeFuture;


import java.io.IOException;
import java.util.Random;
import java.util.concurrent.*;

/**
 * @className: ComparePrice
 * @Description:
 * @Author: wangyifei
 * @Date: 2022/9/16 19:51
 */
public class ComparePrice {
    public static void main(String[] args) {
        long start, end;
        start = System.currentTimeMillis();
        /**
         * Thread 的任务编排，例如，A 和 B 之间又依赖关系，A 和 B 都执行为之后，C 执行。
         * 这样的关系如何编排呢?
         *
         * supplyAsync(Supplier<T>) 生产者，可以认为是第一个执行的认为。supplier 会被 CompletableFuture 的线程执行。
         * runAsync(Runnable) 这个就行执行 Runnable
         * thenApply(Function<IN , OUT>): 接收上游的结果，并执行后面的认为。
         *
         * join() 和 get() 两个方法都是等待执行结果，join 已经把异常处理了。
         *
         * thenAccept(Conusmer<IN>) 接收上游的结果，然后执行
         *
         * */

        CompletableFuture<Double> futureTM = CompletableFuture.supplyAsync(()->priceOfTM());
        CompletableFuture<Double> futureTB = CompletableFuture.supplyAsync(()->priceOfTB());
        CompletableFuture<Double> futureJD = CompletableFuture.supplyAsync(()->priceOfJD());

        CompletableFuture.allOf(futureTM, futureTB, futureJD).join();

        CompletableFuture.supplyAsync(()->{
                    Double rs = 0D ;
                    try {
                        Double tm = futureTM.get();
                        Double jd = futureJD.get();
                        Double tb = futureTB.get();
                        rs = Math.min(tm , Math.min(jd , tb));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (ExecutionException e) {
                        e.printStackTrace();
                    }
                    return rs ;
                })
                .thenApply(String::valueOf)
                .thenApply(str-> "price " + str)
                .thenAccept(System.out::println);

        end = System.currentTimeMillis();
        System.out.println("use completable future! " + (end - start));
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private static double priceOfTM() {
        delay();
        return 1.00;
    }

    private static double priceOfTB() {
        delay();
        return 2.00;
    }

    private static double priceOfJD() {
        delay();
        return 3.00;
    }

    /*private static double priceOfAmazon() {
        delay();
        throw new RuntimeException("product not exist!");
    }*/

    private static void delay() {
        int time = new Random().nextInt(500);
        try {
            TimeUnit.MILLISECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("After %s sleep!\n", time);
    }
}
